package org.cliff.message.platform.core.resend;

import cn.hutool.core.exceptions.ExceptionUtil;
import org.cliff.message.platform.core.domain.*;
import org.cliff.message.platform.core.domain.*;
import org.cliff.message.platform.core.service.InterfaceConfigMaintainer;
import org.cliff.message.platform.core.service.ReceivedMessageResendService;
import org.cliff.message.platform.core.service.ReceivedMessageService;
import org.cliff.message.platform.core.util.UriUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.util.Date;

/**
 * 接收到消息重发任务
 * 
 * @author 刘文
 * @date 2023/10/26
 */
@Slf4j
public class ReceivedMessageResendTask implements Runnable {

    /**
     * 在发送过程中因为异常等原因而重发失败的状态码
     */
    public static final int RESEND_FAILED_STATUS_CODE = 9999;

    private final ReceivedMessageResendDetail resendDetail;

    private final ReceivedMessageResendService resendService;

    private final ReceivedMessageService receivedMessageService;

    private final RestTemplate restTemplate;

    public ReceivedMessageResendTask(ReceivedMessageResendDetail resendDetail,
        ReceivedMessageResendService resendService, ReceivedMessageService receivedMessageService,
        RestTemplate restTemplate) {
        this.resendDetail = resendDetail;
        this.resendService = resendService;
        this.receivedMessageService = receivedMessageService;
        this.restTemplate = restTemplate;
    }

    @Override
    public void run() {
        ReceivedMessage resendMessage = receivedMessageService.getById(resendDetail.getMessageId());
        InterfaceConfig interfaceConfig =
            InterfaceConfigMaintainer.getInterfaceConfigByFunctionCode(resendMessage.getFunctionCode());
        // 新添加的接口，当前节点还没加载，等下一个节点
        if (interfaceConfig == null) {
            log.warn("Interface info {} is not maintained, ignore it.", resendMessage.getFunctionCode());
            return;
        }

        resendService.updateStatusToTriggered(resendDetail);
        if (interfaceConfig.getApplicationName() == null) {
            log.error("Application name is not found in function code: {}", interfaceConfig.getFunctionCode());
            return;
        }

        // 发送消息处理
        long startTime = System.currentTimeMillis();
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType mediaType = resendMessage.getContentType() == null ? MediaType.TEXT_HTML
                    : MediaType.parseMediaType(resendMessage.getContentType());
            headers.setContentType(mediaType);
            headers.add(MPRequestHeaderConstants.RESEND_MESSAGE_ID, resendMessage.getId().toString());
            if (resendDetail.getAutoRetryCount() != null) {
                headers.add(MPRequestHeaderConstants.AUTO_RETRY_COUNT, resendDetail.getAutoRetryCount().toString());
            }
            String body = resendMessage.getJsonBody() == null ? resendMessage.getRequestBody()
                    : resendMessage.getJsonBody().toString();
            HttpEntity<String> entity = new HttpEntity<>(body, headers);
            resendDetail.setRequestTime(new Date());
            ResponseEntity<String> responseEntity = restTemplate.exchange("http://" + interfaceConfig.getApplicationName()
                    + UriUtils.getUriPathFromUrl(resendMessage.getRequestUri()), HttpMethod.POST, entity, String.class);
            resendDetail.setResponseDetail(responseEntity.getBody());
            resendDetail.setStatusCode(responseEntity.getStatusCode().value());
        } catch (Exception e) {
            log.error("Resend failed.", e);
            resendDetail.setResponseDetail(ExceptionUtil.stacktraceToString(e));
            resendDetail.setStatusCode(RESEND_FAILED_STATUS_CODE);
            // 发送失败，自动重发
            resendService.autoResendMessage(resendMessage, interfaceConfig,
                resendDetail.getAutoRetryCount() == null ? 0 : resendDetail.getAutoRetryCount());
        }finally {
            resendDetail.setSendStatus(SendStatusConstants.FINISHED);
            resendDetail.setResponseTime(new Date());
            resendDetail.setProcessTime(System.currentTimeMillis() - startTime);
            resendService.updateRecordWhenResendFinished(resendDetail);
        }
    }
}
